package uid.elements;

/**
 * @author Patricia Vilain
 */

import java.util.ArrayList;
import java.util.List;


import uid.jsf.Componente;
import uid.jsf.Composite;
import uid.jsf.OutputLabel;
import uid.jsf.PanelGrid;

public abstract class Structure extends UIDElement {

	public static final int SINGLE = 1;
	public static final int SET = 2;
	public static final int OPTIONAL = 3;
	protected String name;
	private int type = SINGLE;
	private int cardinalityMin;
	private int cardinalityMax;
	private boolean optional = false;

	protected List<DataItem> listDataItems;
	protected List<Structure> listStructures;

	/**
	 * A estrutura e' criada, por default, como uma estrutura simples (single).
	 */
	public Structure(String name) {
		this.name = name;
		this.type = SINGLE;
		this.listDataItems = new ArrayList<DataItem>();
		this.listStructures = new ArrayList<Structure>();
	}

	public String getName() {
		return name;
	}

	public int getCardinalityMax() {
		return cardinalityMax;
	}

	public void setCardinalityMax(int cardinalityMax) {
		this.cardinalityMax = cardinalityMax;
	}

	public int getCardinalityMin() {
		return cardinalityMin;
	}

	public void setCardinalityMin(int cardinalityMin) {
		this.cardinalityMin = cardinalityMin;
	}

	public int getType() {
		return this.type;
	}

	public void definesAsOptional() {
		this.type = OPTIONAL;
	}

	public void definesAsSet() {
		this.type = SET;
	}

	/**
	 * Insert a data item in the structure if its name is nameStructure. If the
	 * name of the structure is different but it contains others structures, the
	 * internal structures will be analysed.
	 * 
	 * @param nameStructure
	 * @param dataItem
	 * @return
	 */
	public void insertDataItemInStructureOrSubStructure(String nameStructure,
			DataItem dataItem) {
		if (this.name.equals(nameStructure))
			this.insertDataItem(dataItem);
		else if (this.listStructures.size() > 0) {
			for (int i = 0; i < this.listStructures.size(); i++) {
				Structure struct = this.listStructures.get(i);
				struct.insertDataItemInStructureOrSubStructure(nameStructure,
						dataItem);
			}
		}
	}

	/**
	 * Insert a data item in the structure.
	 * 
	 * @param dataItem
	 * @return
	 */
	public void insertDataItem(DataItem dataItem) {
		for (int i = 0; i < this.listDataItems.size(); i++) {
			DataItem item = this.listDataItems.get(i);
			if (item.getName().equals(dataItem.getName()))
				throw new UIDException(UIDException.EXISTING_DATA_ITEM,
						"There is already a data item with this name");
		}
		this.listDataItems.add(dataItem);
	}

	public List<DataItem> getDataItems() {
		return this.listDataItems;
	}

	/**
	 * Insert s sub-structure in the structure.
	 * 
	 * @param dataItem
	 * @return
	 */
	public void insertStructure(Structure structure) {
		for (int i = 0; i < this.listStructures.size(); i++) {
			Structure struct = this.listStructures.get(i);
			if (struct.getName().equals(struct.getName()))
				throw new UIDException(UIDException.EXISTING_STRUCTURE,
						"There is already a structure with this name");
		}
		this.listStructures.add(structure);
	}

	/**
	 * Insert a structure in the structure if its name is nameStructure. If the
	 * name of the structure is different but it contains others structures, the
	 * internal structures will be analysed.
	 * 
	 * @param nameStructure
	 * @param structure
	 * @return
	 */
	public void insertStructureInStructureOrSubStructure(String nameStructure,
			Structure structure) {
		if (this.name.equals(nameStructure))
			this.insertStructure(structure);
		else if (this.listStructures.size() > 0) {
			for (int i = 0; i < this.listStructures.size(); i++) {
				Structure struct = this.listStructures.get(i);
				struct.insertStructureInStructureOrSubStructure(nameStructure,
						structure);
			}
		}
	}

	public List<Structure> getStructures() {
		return this.listStructures;
	}

	public void setOptional(boolean optional) {
		this.optional = optional;
	}

	public boolean isOptional() {
		return optional;
	}

	public boolean contensDataItem(String item) {

		for (DataItem d : listDataItems) {
			if (d.getName().equals(item))
				return true;
		}

		return false;
	}

	public DataItem getDataItem(String item) {

		for (DataItem d : listDataItems) {
			if (d.getName().equals(item))
				return d;
		}

		return null;

	}

	public List<Structure> getAllStructuresAndInternalStructures() {
		List<Structure> structures = new ArrayList<Structure>();

		for (Structure str : this.listStructures) {
			structures.add(str);
			structures.addAll(str.getAllStructuresAndInternalStructures());
		}

		return structures;
	}
}
